home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / VideoSource.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-25  |  38.6 KB  |  1,529 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <crtdbg.h>
  19.  
  20. #include <windows.h>
  21. #include <vfw.h>
  22.  
  23. #include "VideoSource.h"
  24. #include "VBitmap.h"
  25. #include "AVIStripeSystem.h"
  26. #include "ProgressDialog.h"
  27. #include "MJPEGDecoder.h"
  28. #include "crash.h"
  29.  
  30. #include "error.h"
  31. #include "misc.h"
  32. #include "oshelper.h"
  33. #include "helpfile.h"
  34. #include "resource.h"
  35.  
  36. ///////////////////////////
  37.  
  38. extern const char *LookupVideoCodec(FOURCC);
  39.  
  40. extern HINSTANCE g_hInst;
  41. extern HWND g_hWnd;
  42.  
  43. ///////////////////////////
  44.  
  45. const char g_szNoMPEG4Test[]="No MPEG-4 Test";
  46.  
  47. static BOOL CALLBACK MP4CodecWarningDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) {
  48.     switch(msg) {
  49.     case WM_INITDIALOG:
  50.         return TRUE;
  51.     case WM_COMMAND:
  52.         switch(LOWORD(wParam)) {
  53.         case IDOK:
  54.             HelpContext(hdlg, IDH_WARN_MPEG4);
  55.         case IDCANCEL:
  56.             if (IsDlgButtonChecked(hdlg, IDC_NOMORE))
  57.                 SetConfigDword(NULL, g_szNoMPEG4Test, 1);
  58.             EndDialog(hdlg, 0);
  59.             break;
  60.         }
  61.         break;
  62.     }
  63.     return FALSE;
  64. }
  65.  
  66. static bool CheckMPEG4Codec(HIC hic, bool isV3) {
  67.     char frame[0x380];
  68.     BITMAPINFOHEADER bih;
  69.     DWORD dw;
  70.  
  71.     if (QueryConfigDword(NULL, g_szNoMPEG4Test, &dw) && dw)
  72.         return true;
  73.  
  74.     // Form a completely black frame if it's V3.
  75.  
  76.     bih.biSize            = 40;
  77.     bih.biWidth            = 320;
  78.     bih.biHeight        = 240;
  79.     bih.biPlanes        = 1;
  80.     bih.biBitCount        = 24;
  81.     bih.biCompression    = '24PM';
  82.     bih.biSizeImage        = 0;
  83.     bih.biXPelsPerMeter    = 0;
  84.     bih.biYPelsPerMeter    = 0;
  85.     bih.biClrUsed        = 0;
  86.     bih.biClrImportant    = 0;
  87.  
  88.     if (isV3) {
  89.         int i;
  90.  
  91.         frame[0] = (char)0x3f;
  92.         frame[1] = (char)0x71;
  93.         frame[2] = (char)0x1b;
  94.         frame[3] = (char)0x7c;
  95.  
  96.         for(i=4; i<0x179; i+=5) {
  97.             frame[i+0] = (char)0x2f;
  98.             frame[i+1] = (char)0x0b;
  99.             frame[i+2] = (char)0xc2;
  100.             frame[i+3] = (char)0xf0;
  101.             frame[i+4] = (char)0xbc;
  102.         }
  103.  
  104.         frame[0x179] = (char)0xf0;
  105.         frame[0x17a] = (char)0xb8;
  106.         frame[0x17b] = (char)0x01;
  107.  
  108.         bih.biCompression    = '34PM';
  109.         bih.biSizeImage        = 0x17c;
  110.     }
  111.  
  112.     // Attempt to decompress.
  113.  
  114.     HANDLE h;
  115.  
  116.     h = ICImageDecompress(hic, 0, (BITMAPINFO *)&bih, frame, NULL);
  117.  
  118. //    if (!h)
  119. //        DialogBox(g_hInst, MAKEINTRESOURCE(IDD_WARN_MPEG4), g_hWnd, MP4CodecWarningDlgProc);
  120. //    else
  121. //        GlobalFree(h);
  122.  
  123.     if (h) {
  124.         GlobalFree(h);
  125.         return true;
  126.     } else {
  127.         return false;
  128.     }
  129. }
  130.  
  131. ///////////////////////////
  132.  
  133. VideoSource::VideoSource() {
  134.     lpvBuffer = NULL;
  135.     hBufferObject = NULL;
  136.     bmihDecompressedFormat = NULL;
  137. }
  138.  
  139. VideoSource::~VideoSource() {
  140.     freemem(bmihDecompressedFormat);
  141.     FreeFrameBuffer();
  142. }
  143.  
  144. void *VideoSource::AllocFrameBuffer(long size) {
  145.     hBufferObject = CreateFileMapping(
  146.             (HANDLE)0xFFFFFFFF,
  147.             NULL,
  148.             PAGE_READWRITE,
  149.             0,
  150.             size,
  151.             NULL);
  152.  
  153.     if (!hBufferObject) return NULL;
  154.  
  155.     lBufferOffset = 0;
  156.  
  157.     lpvBuffer = MapViewOfFile(hBufferObject, FILE_MAP_ALL_ACCESS, 0, lBufferOffset, size);
  158.  
  159.     if (!lpvBuffer) {
  160.         CloseHandle(hBufferObject);
  161.         hBufferObject = NULL;
  162.     }
  163.  
  164.     return lpvBuffer;
  165. }
  166.  
  167. void VideoSource::FreeFrameBuffer() {
  168.     if (hBufferObject) {
  169.         if (lpvBuffer)
  170.             UnmapViewOfFile(lpvBuffer);
  171.         CloseHandle(hBufferObject);
  172.     } else
  173.         freemem(lpvBuffer);
  174.  
  175.     lpvBuffer = NULL;
  176.     hBufferObject = NULL;
  177. }
  178.  
  179. bool VideoSource::setDecompressedFormat(int depth) {
  180.     memcpy(bmihDecompressedFormat, getImageFormat(), getFormatLen());
  181.     bmihDecompressedFormat->biSize            = sizeof(BITMAPINFOHEADER);
  182.     bmihDecompressedFormat->biPlanes            = 1;
  183.     bmihDecompressedFormat->biBitCount        = depth;
  184.     bmihDecompressedFormat->biCompression    = BI_RGB;
  185.     bmihDecompressedFormat->biSizeImage        = ((bmihDecompressedFormat->biWidth * depth + 31)/32)*4*bmihDecompressedFormat->biHeight;
  186.  
  187.     if (depth>8) {
  188.         bmihDecompressedFormat->biClrUsed        = 0;
  189.         bmihDecompressedFormat->biClrImportant    = 0;
  190.     }
  191.  
  192.     invalidateFrameBuffer();
  193.  
  194.     return true;
  195. }
  196.  
  197. bool VideoSource::setDecompressedFormat(BITMAPINFOHEADER *pbih) {
  198.     if (pbih->biCompression == BI_RGB) {
  199.         setDecompressedFormat(pbih->biBitCount);
  200.         return true;
  201.     }
  202.  
  203.     return false;
  204. }
  205.  
  206. void VideoSource::streamBegin(bool) {
  207.     stream_current_frame    = -1;
  208. }
  209.  
  210. void VideoSource::streamSetDesiredFrame(long frame_num) {
  211.     long key;
  212.  
  213.     key = isKey(frame_num) ? frame_num : prevKey(frame_num);
  214.     if (key<0) key = lSampleFirst;
  215.  
  216.     stream_desired_frame    = frame_num;
  217.  
  218.     if (stream_current_frame<key || stream_current_frame>frame_num)
  219.         stream_current_frame    = key-1;
  220.  
  221. }
  222.  
  223. long VideoSource::streamGetNextRequiredFrame(BOOL *is_preroll) {
  224.     if (stream_current_frame == stream_desired_frame) {
  225.         *is_preroll = FALSE;
  226.  
  227.         return -1;
  228.     }
  229.  
  230.     *is_preroll = (++stream_current_frame != stream_desired_frame);
  231.  
  232.     return stream_current_frame;
  233. }
  234.  
  235. int VideoSource::streamGetRequiredCount(long *pSize) {
  236.  
  237.     if (pSize) {
  238.         long current = stream_current_frame;
  239.         long size = 0, onesize;
  240.         long samp;
  241.  
  242.         while(current < stream_desired_frame) {
  243.             if (AVIERR_OK == read(current, 1, NULL, NULL, &onesize, &samp))
  244.                 size += onesize;
  245.  
  246.             ++current;
  247.         }
  248.  
  249.         *pSize = size;
  250.     }
  251.  
  252.     return stream_desired_frame - stream_current_frame;
  253. }
  254.  
  255. void VideoSource::invalidateFrameBuffer() {
  256. }
  257.  
  258. bool VideoSource::isKeyframeOnly() {
  259.    return false;
  260. }
  261.  
  262. bool VideoSource::isType1() {
  263.    return false;
  264. }
  265.  
  266. ///////////////////////////
  267.  
  268. VideoSourceAVI::VideoSourceAVI(IAVIReadHandler *pAVI, AVIStripeSystem *stripesys, IAVIReadHandler **stripe_files, bool use_internal, int mjpeg_mode, FOURCC fccForceVideo, FOURCC fccForceVideoHandler) {
  269.     pAVIFile    = pAVI;
  270.     pAVIStream    = NULL;
  271.     lpvBuffer    = NULL;
  272.     hicDecomp    = NULL;
  273.     bmihTemp    = NULL;
  274.     key_flags    = NULL;
  275.     mjpeg_reorder_buffer = NULL;
  276.     mjpeg_reorder_buffer_size = 0;
  277.     mjpeg_splits = NULL;
  278.     mjpeg_last = -1;
  279.     this->fccForceVideo = fccForceVideo;
  280.     this->fccForceVideoHandler = fccForceVideoHandler;
  281.     hbmLame = NULL;
  282.     fUseGDI = false;
  283.  
  284.     // striping...
  285.  
  286.     stripe_streams    = NULL;
  287.     stripe_index    = NULL;
  288.     this->stripesys = stripesys;
  289.     this->stripe_files = stripe_files;
  290.     this->use_internal = use_internal;
  291.     this->mjpeg_mode    = mjpeg_mode;
  292.  
  293.     mdec = NULL;
  294.  
  295.     try {
  296.         _construct();
  297.     } catch(...) {
  298.         _destruct();
  299.         throw;
  300.     }
  301. }
  302.  
  303. void VideoSourceAVI::_destruct() {
  304.     delete stripe_index;
  305.  
  306.     if (stripe_streams) {
  307.         int i;
  308.  
  309.         for(i=0; i<stripe_count; i++)
  310.             if (stripe_streams[i])
  311.                 delete stripe_streams[i];
  312.  
  313.         delete stripe_streams;
  314.     }
  315.  
  316.     if (bmihTemp) freemem(bmihTemp);
  317.     if (hicDecomp) ICClose(hicDecomp);
  318.  
  319.     if (pAVIStream) delete pAVIStream;
  320.  
  321.     delete mdec;
  322.     freemem(mjpeg_reorder_buffer);
  323.     mjpeg_reorder_buffer = NULL;
  324.     delete[] mjpeg_splits;
  325.     mjpeg_splits = NULL;
  326.  
  327.     delete[] key_flags; key_flags = NULL;
  328.  
  329.     if (hbmLame) {
  330.         DeleteObject(hbmLame);
  331.         hbmLame = NULL;
  332.     }
  333. }
  334.  
  335. VideoSourceAVI::~VideoSourceAVI() {
  336.     _destruct();
  337. }
  338.  
  339. void VideoSourceAVI::_construct() {
  340.     LONG format_len;
  341.     BITMAPINFOHEADER *bmih;
  342.     bool is_mjpeg, is_dib;
  343.  
  344.     // Look for a standard vids stream
  345.  
  346.     bIsType1 = false;
  347.     pAVIStream = pAVIFile->GetStream(streamtypeVIDEO, 0);
  348.     if (!pAVIStream) {
  349.         pAVIStream = pAVIFile->GetStream('svai', 0);
  350. /*        if (pAVIStream) {
  351.             delete pAVIStream;
  352.             pAVIStream = NULL;
  353.             throw MyError("Type-1 DV files are not currently supported by VirtualDub.");
  354.         }*/
  355.  
  356.         if (!pAVIStream)
  357.             throw MyError("No video stream found.");
  358.  
  359.         bIsType1 = true;
  360.     }
  361.  
  362.     if (pAVIStream->Info(&streamInfo, sizeof streamInfo))
  363.         throw MyError("Error obtaining video stream info.");
  364.  
  365.     // ADDITION FOR STRIPED AVI SUPPORT:
  366.     //
  367.     // If this is an index for a stripe system, then the video stream will have
  368.     // 'VDST' as its fccHandler and video compression.  This will probably
  369.     // correspond to the "VDub Frameserver" compressor, but since VirtualDub can
  370.     // connect to its own frameservers more efficiently though the AVIFile
  371.     // interface, it makes sense to open striped files in native mode.
  372.     //
  373.     // For this to work, we must have been sent the striping specs beforehand,
  374.     // or else we won't be able to open the stripes.
  375.  
  376.     if (streamInfo.fccHandler == 'TSDV') {
  377.         int i;
  378.  
  379.         if (!stripesys)
  380.             throw MyError("AVI file is striped - must be opened with stripe definition file.");
  381.  
  382.         // allocate memory for stripe stream table
  383.  
  384.         stripe_count = stripesys->getStripeCount();
  385.  
  386.         if (!(stripe_streams = new IAVIReadStream *[stripe_count]))
  387.             throw MyMemoryError();
  388.  
  389.         for(i=0; i<stripe_count; i++)
  390.             stripe_streams[i] = NULL;
  391.  
  392.         // attempt to open a video stream for every stripe that has one
  393.  
  394.         format_stream = NULL;
  395.  
  396.         for(i=0; i<stripe_count; i++) {
  397.             if (stripesys->getStripeInfo(i)->isVideo()) {
  398.                 stripe_streams[i] = stripe_files[i]->GetStream(streamtypeVIDEO, 0);
  399.                 if (!stripe_streams[i])
  400.                     throw MyError("Striping: cannot open video stream for stripe #%d", i+1);
  401.  
  402.                 if (!format_stream) format_stream = stripe_streams[i];
  403.             }
  404.         }
  405.  
  406.         if (!format_stream)
  407.             throw MyError("Striping: No video stripes found!");
  408.  
  409.         // Reread the streamInfo structure from first video stripe,
  410.         // because ours is fake.
  411.  
  412.         if (format_stream->Info(&streamInfo, sizeof streamInfo))
  413.             throw MyError("Error obtaining video stream info from first video stripe.");
  414.  
  415.         // Initialize the index.
  416.  
  417.         if (!(stripe_index = new AVIStripeIndexLookup(pAVIStream)))
  418.             throw MyMemoryError();
  419.         
  420.     } else {
  421.         if (stripesys)
  422.             throw MyError("This is not a striped AVI file.");
  423.  
  424.         format_stream = pAVIStream;
  425.     }
  426.  
  427.     // Read video format.  If we're striping, the index stripe has a fake
  428.     // format, so we have to grab the format from a video stripe.  If it's a
  429.     // type-1 DV, we're going to have to fake it.
  430.  
  431.     if (bIsType1) {
  432.         format_len = sizeof(BITMAPINFOHEADER);
  433.  
  434.         if (!(bmih = (BITMAPINFOHEADER *)allocFormat(format_len))) throw MyMemoryError();
  435.  
  436.         bmih->biSize            = sizeof(BITMAPINFOHEADER);
  437.         bmih->biWidth            = 720;
  438.  
  439.         if (streamInfo.dwRate > streamInfo.dwScale*26i64)
  440.             bmih->biHeight            = 480;
  441.         else
  442.             bmih->biHeight            = 576;
  443.  
  444.         bmih->biPlanes            = 1;
  445.         bmih->biBitCount        = 24;
  446.         bmih->biCompression        = 'dsvd';
  447.         bmih->biSizeImage        = streamInfo.dwSuggestedBufferSize;
  448.         bmih->biXPelsPerMeter    = 0;
  449.         bmih->biYPelsPerMeter    = 0;
  450.         bmih->biClrUsed            = 0;
  451.         bmih->biClrImportant    = 0;
  452.     } else {
  453.         format_stream->FormatSize(0, &format_len);
  454.  
  455.         if (!(bmih = (BITMAPINFOHEADER *)allocFormat(format_len))) throw MyMemoryError();
  456.  
  457.         if (format_stream->ReadFormat(0, getFormat(), &format_len))
  458.             throw MyError("Error obtaining video stream format.");
  459.     }
  460.     if (!(bmihTemp = (BITMAPINFOHEADER *)allocmem(format_len))) throw MyMemoryError();
  461.     if (!(bmihDecompressedFormat = (BITMAPINFOHEADER *)allocmem(format_len))) throw MyMemoryError();
  462.  
  463.     // We can handle RGB8/16/24/32 and YUY2.
  464.  
  465.     is_dib = (bmih->biCompression == BI_RGB) || (bmih->biCompression == '2YUY');
  466.  
  467.     // Force the video format if necessary
  468.  
  469.     if (fccForceVideo)
  470.         getImageFormat()->biCompression = fccForceVideo;
  471.  
  472.     if (fccForceVideoHandler)
  473.         streamInfo.fccHandler = fccForceVideoHandler;
  474.  
  475.     is_mjpeg = isEqualFOURCC(bmih->biCompression, 'GPJM')
  476.             || isEqualFOURCC(fccForceVideo, 'GPJM')
  477.             || isEqualFOURCC(bmih->biCompression, '1bmd')
  478.             || isEqualFOURCC(fccForceVideo, '1bmd');
  479.  
  480.     // If this is MJPEG, check to see if we should modify the output format and/or stream info
  481.  
  482.     lSampleFirst = pAVIStream->Start();
  483.     lSampleLast = pAVIStream->End();
  484.  
  485.     if (is_mjpeg) {
  486.         BITMAPINFOHEADER *pbih = getImageFormat();
  487.  
  488.         if (mjpeg_mode && mjpeg_mode != IFMODE_SWAP && pbih->biHeight > 288) {
  489.             pbih->biHeight /= 2;
  490.  
  491.             if (mjpeg_mode == IFMODE_SPLIT1 || mjpeg_mode == IFMODE_SPLIT2) {
  492.                 streamInfo.dwRate *= 2;
  493.                 streamInfo.dwLength *= 2;
  494.                 lSampleLast = lSampleLast*2 - lSampleFirst;
  495.             }
  496.         }
  497.  
  498.         if (mjpeg_mode) {
  499.             if (!(mjpeg_splits = new long[lSampleLast - lSampleFirst]))
  500.                 throw MyMemoryError();
  501.  
  502.             for(int i=0; i<lSampleLast-lSampleFirst; i++)
  503.                 mjpeg_splits[i] = -1;
  504.         }
  505.     } else
  506.         mjpeg_mode = 0;
  507.  
  508.     memcpy(bmihTemp, getFormat(), format_len);
  509.  
  510.     // allocate framebuffer
  511.  
  512.     if (!AllocFrameBuffer(bmih->biWidth * 4 * bmih->biHeight + 4))
  513.         throw MyMemoryError();
  514.  
  515.     // get a decompressor
  516.     //
  517.     // 'DIB ' is the official value for uncompressed AVIs, but some stupid
  518.     // programs also use (null) and 'RAW '
  519.  
  520.     hicDecomp = NULL;
  521.  
  522.     if (bmih->biCompression == BI_BITFIELDS || bmih->biCompression == BI_RLE8 || bmih->biCompression == BI_RLE4
  523.         || (bmih->biCompression == BI_RGB && bmih->biBitCount<16 && bmih->biBitCount != 8)) {
  524.  
  525.         // Ugh.  It's one of them weirdo formats.  Let GDI handle it!
  526.  
  527.         fUseGDI = true;
  528.  
  529.     } else if (!is_dib) {
  530.         FOURCC fccOriginalCodec = bmih->biCompression;
  531.  
  532.         // If it's a hacked MPEG-4 driver, try all of the known hacks. #*$&@#(&$)(#$
  533.         // They're all the same driver, so they're mutually compatible.
  534.  
  535.         VDCHECKPOINT;
  536.         switch(bmih->biCompression) {
  537.         case '34PM':        // Microsoft MPEG-4 V3
  538.         case '3VID':        // "DivX Low-Motion" (4.10.0.3917)
  539.         case '4VID':        // "DivX Fast-Motion" (4.10.0.3920)
  540.         case '14PA':        // "AngelPotion Definitive" (4.0.00.3688)
  541.             if (AttemptCodecNegotiation(bmih, is_mjpeg)) return;
  542.             bmih->biCompression = '34PM';
  543.             if (AttemptCodecNegotiation(bmih, is_mjpeg)) return;
  544.             bmih->biCompression = '3VID';
  545.             if (AttemptCodecNegotiation(bmih, is_mjpeg)) return;
  546.             bmih->biCompression = '4VID';
  547.             if (AttemptCodecNegotiation(bmih, is_mjpeg)) return;
  548.             bmih->biCompression = '14PA';
  549.         default:
  550.             if (AttemptCodecNegotiation(bmih, is_mjpeg)) return;
  551.             break;
  552.         }
  553.         VDCHECKPOINT;
  554.  
  555.         const char *s = LookupVideoCodec(fccOriginalCodec);
  556.  
  557.         throw MyError("Couldn't locate decompressor for format '%c%c%c%c' (%s)\n"
  558.                         "\n"
  559.                         "VirtualDub requires a Video for Windows (VFW) compatible codec to decompress "
  560.                         "video. DirectShow codecs, such as those used by Windows Media Player, are not "
  561.                         "suitable."
  562.                     ,(fccOriginalCodec    ) & 0xff
  563.                     ,(fccOriginalCodec>> 8) & 0xff
  564.                     ,(fccOriginalCodec>>16) & 0xff
  565.                     ,(fccOriginalCodec>>24) & 0xff
  566.                     ,s ? s : "unknown");
  567.     }
  568. }
  569.  
  570. bool VideoSourceAVI::AttemptCodecNegotiation(BITMAPINFOHEADER *bmih, bool is_mjpeg) {
  571.  
  572.     // VideoMatrix sets streamInfo.fccHandler to NULL.  Danger, Will Robinson.
  573.  
  574.     if (!use_internal) {
  575.  
  576.         // Try the handler specified in the file first.  In some cases, it'll
  577.         // be wrong or missing.
  578.  
  579.         if (streamInfo.fccHandler)
  580.             hicDecomp = ICOpen(ICTYPE_VIDEO, streamInfo.fccHandler, ICMODE_DECOMPRESS);
  581.  
  582.         if (!hicDecomp || ICERR_OK!=ICDecompressQuery(hicDecomp, bmih, NULL)) {
  583.             if (hicDecomp)
  584.                 ICClose(hicDecomp);
  585.  
  586.             // Pick a handler based on the biCompression field instead.
  587.  
  588.             hicDecomp = ICOpen(ICTYPE_VIDEO, bmih->biCompression, ICMODE_DECOMPRESS);
  589.  
  590.             if (!hicDecomp || ICERR_OK!=ICDecompressQuery(hicDecomp, bmih, NULL)) {
  591.                 if (hicDecomp)
  592.                     ICClose(hicDecomp);
  593.  
  594.                 // AngelPotion f*cks us over here and overwrites our format if we keep this in.
  595.                 // So let's write protect the format.  You'll see a nice C0000005 error when
  596.                 // the AP DLL tries to modify it.
  597.  
  598. //                hicDecomp = ICLocate(ICTYPE_VIDEO, NULL, getImageFormat(), NULL, ICMODE_DECOMPRESS);
  599.  
  600.                 int siz = getFormatLen();
  601.  
  602.                 BITMAPINFOHEADER *pbih_protected = (BITMAPINFOHEADER *)VirtualAlloc(NULL, siz, MEM_COMMIT, PAGE_READWRITE);
  603.  
  604.                 if (pbih_protected) {
  605.                     DWORD dwOldProtect;
  606.  
  607.                     memcpy(pbih_protected, bmih, siz);
  608.                     VirtualProtect(pbih_protected, siz, PAGE_READONLY, &dwOldProtect);
  609.  
  610.                     hicDecomp = ICLocate(ICTYPE_VIDEO, NULL, pbih_protected, NULL, ICMODE_DECOMPRESS);
  611.  
  612.                     VirtualFree(pbih_protected, 0, MEM_RELEASE);
  613.                 }
  614.             }
  615.         }
  616.     }
  617.  
  618.     if (!hicDecomp) {
  619.  
  620.         // Is it MJPEG or I420?  Maybe we can do it ourselves.
  621.  
  622.         if (is_mjpeg) {
  623.             if (!(mdec = CreateMJPEGDecoder(getImageFormat()->biWidth, getImageFormat()->biHeight)))
  624.                 throw MyMemoryError();
  625.  
  626.             return true;
  627.         } else {
  628.             return false;
  629.         }
  630.     } else {
  631.  
  632.         // check for bad MPEG-4 V2/V3 codec
  633.  
  634.         if (isEqualFOURCC(bmih->biCompression, '24PM'))
  635.             return CheckMPEG4Codec(hicDecomp, false);
  636.         else if (isEqualFOURCC(bmih->biCompression, '34PM'))
  637.             return CheckMPEG4Codec(hicDecomp, true);
  638.         else
  639.             return true;
  640.     }
  641. }
  642.  
  643. ///////////////////////////////////////////////////////////////////////////
  644.  
  645. void VideoSourceAVI::Reinit() {
  646.     long nOldFrames, nNewFrames;
  647.  
  648.     nOldFrames = lSampleLast - lSampleFirst;
  649.     nNewFrames = pAVIStream->End() - pAVIStream->Start();
  650.  
  651.     if (mjpeg_splits) {
  652.         nOldFrames >>= 1;
  653.     }
  654.  
  655.     if (nOldFrames != nNewFrames && (mjpeg_mode==IFMODE_SPLIT1 || mjpeg_mode==IFMODE_SPLIT2)) {
  656.         // We have to resize the mjpeg_splits array.
  657.  
  658.         long *pNewSplits = new long[lSampleLast - lSampleFirst];
  659.  
  660.         if (!pNewSplits)
  661.             throw MyMemoryError();
  662.  
  663.         int i;
  664.  
  665.         memcpy(pNewSplits, mjpeg_splits, sizeof(long)*nOldFrames);
  666.  
  667.         for(i=nOldFrames; i<nNewFrames; i++)
  668.             pNewSplits[i] = -1;
  669.  
  670.         delete[] mjpeg_splits;
  671.  
  672.         mjpeg_splits = pNewSplits;
  673.     }
  674.  
  675.     if (pAVIStream->Info(&streamInfo, sizeof streamInfo))
  676.         throw MyError("Error obtaining video stream info.");
  677.  
  678.     lSampleFirst = pAVIStream->Start();
  679.  
  680.     if (mjpeg_splits) {
  681.         streamInfo.dwRate *= 2;
  682.         streamInfo.dwLength *= 2;
  683.         lSampleLast = pAVIStream->End() * 2 - lSampleFirst;
  684.     } else
  685.         lSampleLast = pAVIStream->End();
  686.  
  687.     streamInfo.dwLength        = lSampleLast - lSampleFirst;
  688. }
  689.  
  690. void VideoSourceAVI::redoKeyFlags() {
  691.     long lSample;
  692.     long lMaxFrame=0;
  693.     long lActualBytes, lActualSamples;
  694.     int err;
  695.     void *lpInputBuffer = NULL;
  696.     void *lpKeyBuffer = NULL;
  697.     BOOL fStreamBegun = FALSE;
  698.     int iBytes;
  699.     long *pFrameSums;
  700.  
  701.     if (!hicDecomp)
  702.         return;
  703.  
  704.     iBytes = (lSampleLast+7-lSampleFirst)>>3;
  705.  
  706.     if (!(key_flags = new char[iBytes]))
  707.         throw MyMemoryError();
  708.  
  709.     memset(key_flags, 0, iBytes);
  710.  
  711.     // Find maximum frame
  712.  
  713.     lSample = lSampleFirst;
  714.     while(lSample < lSampleLast) {
  715.         err = _read(lSample, 1, NULL, 0, &lActualBytes, &lActualSamples);
  716.         if (err == AVIERR_OK)
  717. //            throw MyAVIError("VideoSource", err);
  718.  
  719.             if (lActualBytes > lMaxFrame) lMaxFrame = lActualBytes;
  720.  
  721.         ++lSample;
  722.     }
  723.  
  724.     if (!setDecompressedFormat(24))
  725.         if (!setDecompressedFormat(32))
  726.             if (!setDecompressedFormat(16))
  727.                 if (!setDecompressedFormat(8))
  728.                     throw MyError("Video decompressor is incapable of decompressing to an RGB format.");
  729.  
  730.     if (!(lpInputBuffer = new char[((lMaxFrame+7)&-8) + lMaxFrame]))
  731.         throw MyMemoryError();
  732.  
  733.     if (!(pFrameSums = new long[lSampleLast - lSampleFirst])) {
  734.         delete[] lpInputBuffer;
  735.         throw MyMemoryError();
  736.     }
  737.  
  738.     try {
  739.         ProgressDialog pd(NULL, "AVI Import Filter", "Rekeying video stream", (lSampleLast - lSampleFirst)*2, true);
  740.         pd.setValueFormat("Frame %ld of %ld");
  741.  
  742.         streamBegin(true);
  743.         fStreamBegun = TRUE;
  744.  
  745.         lSample = lSampleFirst;
  746.         while(lSample < lSampleLast) {
  747.             long lBlackTotal=0, lWhiteTotal=0;
  748.             long x, y;
  749.             const long lWidth    = (bmihDecompressedFormat->biWidth * bmihDecompressedFormat->biBitCount + 7)/8;
  750.             const long lModulo    = (4-lWidth)&3;
  751.             const long lHeight    = bmihDecompressedFormat->biHeight;
  752.             unsigned char *ptr;
  753.  
  754.             _RPT1(0,"Rekeying frame %ld\n", lSample);
  755.  
  756.             err = _read(lSample, 1, lpInputBuffer, lMaxFrame, &lActualBytes, &lActualSamples);
  757.             if (err != AVIERR_OK)
  758. //                throw MyAVIError("VideoSourceAVI", err);
  759.                 goto rekey_error;
  760.  
  761. #if 0
  762.             // decompress frame with an all black background
  763.  
  764.             memset(lpvBuffer, 0, bmihDecompressedFormat->biSizeImage);
  765.             streamGetFrame(lpInputBuffer, lActualBytes, FALSE, FALSE, lSample);
  766.  
  767.             ptr = (unsigned char *)lpvBuffer;
  768.             y = lHeight;
  769.             do {
  770.                 x = lWidth;
  771.                 do {
  772.                     lBlackTotal += (long)*ptr++;
  773.                 } while(--x);
  774.  
  775.                 ptr += lModulo;
  776.             } while(--y);
  777.  
  778.             // decompress frame with an all white background
  779.  
  780.             memset(lpvBuffer, 0xff, bmihDecompressedFormat->biSizeImage);
  781.             streamGetFrame(lpInputBuffer, lActualBytes, FALSE, FALSE, lSample);
  782.  
  783.             ptr = (unsigned char *)lpvBuffer;
  784.             y = lHeight;
  785.             do {
  786.                 x = lWidth;
  787.                 do {
  788.                     lWhiteTotal += (long)*ptr++;
  789.                 } while(--x);
  790.  
  791.                 ptr += lModulo;
  792.             } while(--y);
  793. #else
  794.  
  795.             streamGetFrame(lpInputBuffer, lActualBytes, FALSE, FALSE, lSample);
  796.  
  797.             ptr = (unsigned char *)lpvBuffer;
  798.             y = lHeight;
  799.             do {
  800.                 x = lWidth;
  801.                 do {
  802.                     lWhiteTotal += (long)*ptr++;
  803.                     lWhiteTotal ^= 0xAAAAAAAA;
  804.                 } while(--x);
  805.  
  806.                 ptr += lModulo;
  807.             } while(--y);
  808.  
  809.  
  810.             pFrameSums[lSample - lSampleFirst] = lWhiteTotal;
  811. #endif
  812.  
  813. //            if (lBlackTotal == lWhiteTotal)
  814. //                key_flags[(lSample - lSampleFirst)>>3] |= 1<<((lSample-lSampleFirst)&7);
  815.  
  816. rekey_error:
  817.             ++lSample;
  818.  
  819.             pd.advance(lSample - lSampleFirst);
  820.             pd.check();
  821.         }
  822.  
  823.         lSample = lSampleFirst;
  824.         do {
  825.             long lBlackTotal=0, lWhiteTotal=0;
  826.             long x, y;
  827.             const long lWidth    = (bmihDecompressedFormat->biWidth * bmihDecompressedFormat->biBitCount + 7)/8;
  828.             const long lModulo    = (4-lWidth)&3;
  829.             const long lHeight    = bmihDecompressedFormat->biHeight;
  830.             unsigned char *ptr;
  831.  
  832.             _RPT1(0,"Rekeying frame %ld\n", lSample);
  833.  
  834.             err = _read(lSample, 1, lpInputBuffer, lMaxFrame, &lActualBytes, &lActualSamples);
  835.             if (err != AVIERR_OK)
  836. //                throw MyAVIError("VideoSourceAVI", err);
  837.                 goto rekey_error2;
  838.  
  839.             streamGetFrame(lpInputBuffer, lActualBytes, FALSE, FALSE, lSample);
  840.  
  841.             ptr = (unsigned char *)lpvBuffer;
  842.             y = lHeight;
  843.             do {
  844.                 x = lWidth;
  845.                 do {
  846.                     lWhiteTotal += (long)*ptr++;
  847.                     lWhiteTotal ^= 0xAAAAAAAA;
  848.                 } while(--x);
  849.  
  850.                 ptr += lModulo;
  851.             } while(--y);
  852.  
  853.  
  854.             if (lWhiteTotal == pFrameSums[lSample - lSampleFirst])
  855.                 key_flags[(lSample - lSampleFirst)>>3] |= 1<<((lSample-lSampleFirst)&7);
  856.  
  857. rekey_error2:
  858.             if (lSample == lSampleFirst)
  859.                 lSample = lSampleLast-1;
  860.             else
  861.                 --lSample;
  862.  
  863.             pd.advance(lSampleLast*2 - (lSample+lSampleFirst));
  864.             pd.check();
  865.         } while(lSample >= lSampleFirst+1);
  866.  
  867.         streamEnd();
  868.     } catch(...) {
  869.         if (fStreamBegun) streamEnd();
  870.         delete[] lpInputBuffer;
  871.         delete[] pFrameSums;
  872.         throw;
  873.     }
  874.  
  875.     delete[] lpInputBuffer;
  876.     delete[] pFrameSums;
  877. }
  878.  
  879. int VideoSourceAVI::_read(LONG lStart, LONG lCount, LPVOID lpBuffer, LONG cbBuffer, LONG *lBytesRead, LONG *lSamplesRead) {
  880.     IAVIReadStream *pSource = pAVIStream;
  881.     bool phase = (lStart - lSampleFirst)&1;
  882.  
  883.     if (mjpeg_mode == IFMODE_SPLIT1 || mjpeg_mode == IFMODE_SPLIT2)
  884.         lStart = lSampleFirst + (lStart - lSampleFirst)/2;
  885.  
  886.     // If we're striping, then we have to lookup the correct stripe for this sample.
  887.  
  888.     if (stripesys) {
  889.         AVIStripeIndexEntry *asie;
  890.         long offset;
  891.  
  892.         if (!(asie = stripe_index->lookup(lStart)))
  893.             return AVIERR_FILEREAD;
  894.  
  895.         offset = lStart - asie->lSampleFirst;
  896.  
  897.         if (lCount > asie->lSampleCount-offset)
  898.             lCount = asie->lSampleCount-offset;
  899.  
  900.         if (!stripe_streams[asie->lStripe])
  901.             return AVIERR_FILEREAD;
  902.  
  903.         pSource = stripe_streams[asie->lStripe];
  904.         lStart = asie->lStripeSample + offset;
  905.     }
  906.  
  907.     // MJPEG modification mode?
  908.  
  909.     if (mjpeg_mode) {
  910.         int res;
  911.         LONG lBytes, lSamples;
  912.         long lRealSample = lStart;
  913.         long lOffset, lLength;
  914.  
  915.         // Did we just read in this sample!?
  916.  
  917.         if (lStart == mjpeg_last) {
  918.             lBytes = mjpeg_last_size;
  919.             res = AVIERR_OK;
  920.         } else {
  921.  
  922.             // Read the sample into memory.  If we don't have a lpBuffer *and* already know
  923.             // where the split is, just get the size.
  924.  
  925.             if (lpBuffer || mjpeg_splits[lStart - lSampleFirst]<0) {
  926.  
  927.                 mjpeg_last = -1;
  928.  
  929.                 if (mjpeg_reorder_buffer_size)
  930.                     res = pSource->Read(lStart, 1, mjpeg_reorder_buffer, mjpeg_reorder_buffer_size, &lBytes, &lSamples);
  931.  
  932.                 if (res == AVIERR_BUFFERTOOSMALL || !mjpeg_reorder_buffer_size) {
  933.                     void *new_buffer;
  934.                     int new_size;
  935.  
  936.                     res = pSource->Read(lStart, 1, NULL, 0, &lBytes, &lSamples);
  937.  
  938.                     if (res == AVIERR_OK) {
  939.  
  940.                         _ASSERT(lBytes != 0);
  941.  
  942.                         new_size = (lBytes + 4095) & -4096;
  943. //                        new_size = lBytes;
  944.                         new_buffer = reallocmem(mjpeg_reorder_buffer, new_size);
  945.  
  946.                         if (!new_buffer)
  947.                             return AVIERR_MEMORY;
  948.  
  949.                         mjpeg_reorder_buffer = new_buffer;
  950.                         mjpeg_reorder_buffer_size = new_size;
  951.  
  952.                         res = pSource->Read(lStart, 1, mjpeg_reorder_buffer, mjpeg_reorder_buffer_size, &lBytes, &lSamples);
  953.                     }
  954.                 }
  955.  
  956.                 if (res == AVIERR_OK) {
  957.                     mjpeg_last = lStart;
  958.                     mjpeg_last_size = lBytes;
  959.                 }
  960.             } else
  961.                 res = pSource->Read(lStart, 1, NULL, 0, &lBytes, &lSamples);
  962.         }
  963.  
  964.  
  965.         if (res != AVIERR_OK) {
  966.             if (lBytesRead)
  967.                 *lBytesRead = 0;
  968.             if (lSamplesRead)
  969.                 *lSamplesRead = 0;
  970.             return res;
  971.         } else if (!lBytes) {
  972.             if (lBytesRead)
  973.                 *lBytesRead = 0;
  974.             if (lSamplesRead)
  975.                 *lSamplesRead = 1;
  976.             return AVIERR_OK;
  977.         }
  978.  
  979.         // Attempt to find SOI tag in sample
  980.  
  981.         lOffset = 0;
  982.         lLength = lBytes;
  983.  
  984.         {
  985.             int i;
  986.  
  987.             // Do we already know where the split is?
  988.  
  989.             if (mjpeg_splits[lStart-lSampleFirst]<0) {
  990.                 for(i=2; i<lBytes-2; i++)
  991.                     if (((unsigned char *)mjpeg_reorder_buffer)[i] == (unsigned char)0xFF
  992.                             && ((unsigned char *)mjpeg_reorder_buffer)[i+1] == (unsigned char)0xD8)
  993.                         break;
  994.  
  995.                 mjpeg_splits[lStart - lSampleFirst] = i;
  996.             } else {
  997.                 i = mjpeg_splits[lStart - lSampleFirst];
  998.             }
  999.  
  1000.             if (i<lBytes-2) {
  1001.                 if (mjpeg_mode != IFMODE_SWAP) {
  1002.                     switch(mjpeg_mode) {
  1003.                     case IFMODE_SPLIT2:
  1004.                         phase = !phase;
  1005.                         break;
  1006.                     case IFMODE_DISCARD1:
  1007.                         phase = false;
  1008.                         break;
  1009.                     case IFMODE_DISCARD2:
  1010.                         phase = true;
  1011.                         break;
  1012.                     }
  1013.  
  1014.                     if (phase) {
  1015.                         lOffset = i;
  1016.                         lLength = lBytes - i;
  1017.                     } else {
  1018.                         lOffset = 0;
  1019.                         lLength = i;
  1020.                     }
  1021.                 } else
  1022.                     lOffset = i;
  1023.             }
  1024.         }
  1025.  
  1026.         if (lpBuffer) {
  1027.             if (lSamplesRead)
  1028.                 *lSamplesRead = 1;
  1029.             if (lBytesRead)
  1030.                 *lBytesRead = lLength;
  1031.  
  1032.             if (cbBuffer < lLength)
  1033.                 return AVIERR_BUFFERTOOSMALL;
  1034.  
  1035.             if (mjpeg_mode == IFMODE_SWAP) {
  1036.                 char *pp1 = (char *)lpBuffer;
  1037.                 char *pp2 = (char *)lpBuffer + (lBytes - lOffset);
  1038.  
  1039.                 memcpy(pp1, (char *)mjpeg_reorder_buffer+lOffset, lBytes - lOffset);
  1040.                 if (lOffset)
  1041.                     memcpy(pp2, mjpeg_reorder_buffer, lOffset);
  1042.  
  1043.                 // patch phase on both MJPEG headers
  1044.  
  1045.                 if (((short *)pp1)[1]==(short)0xE0FF)
  1046.                     pp1[10] = 1;
  1047.  
  1048.                 if (((short *)pp2)[1]==(short)0xE0FF)
  1049.                     pp2[10] = 2;
  1050.                 
  1051.             } else {
  1052.  
  1053.                 memcpy(lpBuffer, (char *)mjpeg_reorder_buffer+lOffset, lLength);
  1054.  
  1055.                 // patch phase on MJPEG header by looking for APP0 tag (xFFE0)
  1056.  
  1057.                 // FFD8 FFE0 0010 'AVI1' polarity
  1058.  
  1059.                 if (((short *)lpBuffer)[1]==(short)0xE0FF)
  1060.                     ((char *)lpBuffer)[10] = 0;
  1061.             }
  1062.  
  1063.             return AVIERR_OK;
  1064.         } else {
  1065.             if (lSamplesRead)
  1066.                 *lSamplesRead = 1;
  1067.             if (lBytesRead)
  1068.                 *lBytesRead = lLength;
  1069.  
  1070.             return AVIERR_OK;
  1071.         }
  1072.  
  1073.     } else
  1074.         return pSource->Read(lStart, lCount, lpBuffer, cbBuffer, lBytesRead, lSamplesRead);
  1075. }
  1076.  
  1077. BOOL VideoSourceAVI::_isKey(LONG samp) {
  1078.     if ((mjpeg_mode & -2) == IFMODE_SPLIT1)
  1079.         samp = lSampleFirst + (samp - lSampleFirst)/2;
  1080.  
  1081.     if (key_flags) {
  1082.         samp -= lSampleFirst;
  1083.  
  1084.         return !!(key_flags[samp>>3] & (1<<(samp&7)));
  1085.     } else
  1086.         return pAVIStream->IsKeyFrame(samp);
  1087. }
  1088.  
  1089. LONG VideoSourceAVI::nearestKey(LONG lSample) {
  1090.     if (key_flags) {
  1091.         if (lSample < lSampleFirst || lSample >= lSampleLast)
  1092.             return -1;
  1093.  
  1094.         if (_isKey(lSample)) return lSample;
  1095.  
  1096.         return prevKey(lSample);
  1097.     }
  1098.  
  1099. //    if (lNear == -1)
  1100. //        throw MyError("VideoSourceAVI: error getting previous key frame");
  1101.  
  1102.     if ((mjpeg_mode & -2) == IFMODE_SPLIT1) {
  1103.         return pAVIStream->NearestKeyFrame(lSampleFirst + (lSample-lSampleFirst)/2)*2-lSampleFirst;
  1104.     } else {
  1105.         return pAVIStream->NearestKeyFrame(lSample);
  1106.     }
  1107. }
  1108.  
  1109. LONG VideoSourceAVI::prevKey(LONG lSample) {
  1110.     if ((mjpeg_mode & -2) == IFMODE_SPLIT1) {
  1111.         lSample = lSampleFirst + (lSample - lSampleFirst)/2;
  1112.  
  1113.         if (key_flags) {
  1114.             if (lSample >= lSampleLast) return -1;
  1115.  
  1116.             while(--lSample >= lSampleFirst)
  1117.                 if (_isKey(lSample)) return lSample*2-lSampleFirst;
  1118.  
  1119.             return -1;
  1120.         } else
  1121.             return pAVIStream->PrevKeyFrame(lSample)*2-lSampleFirst;
  1122.     } else {
  1123.         if (key_flags) {
  1124.             if (lSample >= lSampleLast) return -1;
  1125.  
  1126.             while(--lSample >= lSampleFirst)
  1127.                 if (_isKey(lSample)) return lSample;
  1128.  
  1129.             return -1;
  1130.         } else
  1131.             return pAVIStream->PrevKeyFrame(lSample);
  1132.     }
  1133. }
  1134.  
  1135. LONG VideoSourceAVI::nextKey(LONG lSample) {
  1136.     if ((mjpeg_mode & -2) == IFMODE_SPLIT1) {
  1137.         lSample = lSampleFirst + (lSample - lSampleFirst)/2;
  1138.  
  1139.         if (key_flags) {
  1140.             if (lSample < lSampleFirst) return -1;
  1141.  
  1142.             while(++lSample < lSampleLast)
  1143.                 if (_isKey(lSample)) return lSample*2 - lSampleFirst;
  1144.  
  1145.             return -1;
  1146.         } else
  1147.             return pAVIStream->NextKeyFrame(lSample)*2 - lSampleFirst;
  1148.  
  1149.     } else {
  1150.  
  1151.         if (key_flags) {
  1152.             if (lSample < lSampleFirst) return -1;
  1153.  
  1154.             while(++lSample < lSampleLast)
  1155.                 if (_isKey(lSample)) return lSample;
  1156.  
  1157.             return -1;
  1158.         } else
  1159.             return pAVIStream->NextKeyFrame(lSample);
  1160.  
  1161.     }
  1162. }
  1163.  
  1164. bool VideoSourceAVI::setDecompressedFormat(int depth) {
  1165.     VideoSource::setDecompressedFormat(depth);
  1166.  
  1167.     if (fUseGDI) {
  1168.         void *pv;
  1169.         HDC hdc;
  1170.  
  1171.         if (depth != 24 && depth != 32 && depth != 16)
  1172.             return false;
  1173.  
  1174.         if (hbmLame)
  1175.             DeleteObject(hbmLame);
  1176.  
  1177.         hbmLame = NULL;
  1178.  
  1179.         if (hdc = CreateCompatibleDC(NULL)) {
  1180.             hbmLame = CreateDIBSection(hdc, (BITMAPINFO *)bmihDecompressedFormat, DIB_RGB_COLORS, &pv, hBufferObject, 0);
  1181.             DeleteDC(hdc);
  1182.         }
  1183.  
  1184.         return true;
  1185.  
  1186.     } else if (mdec)
  1187.         return depth == 32 || depth == 16;
  1188.     else if (hicDecomp)
  1189.         return ICERR_OK == ICDecompressQuery(hicDecomp, getImageFormat(), bmihDecompressedFormat);
  1190.     else if (getImageFormat()->biCompression == '024I')
  1191.         return depth == 32;
  1192.     else
  1193.         return depth == 32 || depth == 24 || depth == 16;
  1194. }
  1195.  
  1196. bool VideoSourceAVI::setDecompressedFormat(BITMAPINFOHEADER *pbih) {
  1197.     if (pbih->biCompression == BI_RGB)
  1198.         return setDecompressedFormat(pbih->biBitCount);
  1199.  
  1200.     if (mdec)
  1201.         return false;
  1202.  
  1203.     if (hicDecomp && ICERR_OK == ICDecompressQuery(hicDecomp, getImageFormat(), pbih)) {
  1204.         memcpy(bmihDecompressedFormat, pbih, sizeof(BITMAPINFOHEADER));
  1205.  
  1206.         invalidateFrameBuffer();
  1207.         return true;
  1208.     }
  1209.  
  1210.     return false;
  1211. }
  1212.  
  1213. ////////////////////////////////////////////////
  1214.  
  1215. void DIBconvert(void *src0, BITMAPINFOHEADER *srcfmt, void *dst0, BITMAPINFOHEADER *dstfmt) {
  1216.     if (srcfmt->biCompression == '2YUY')
  1217.         VBitmap(dst0, dstfmt).BitBltFromYUY2(0, 0, &VBitmap(src0, srcfmt), 0, 0, -1, -1);
  1218.     else if (srcfmt->biCompression == '024I')
  1219.         VBitmap(dst0, dstfmt).BitBltFromI420(0, 0, &VBitmap(src0, srcfmt), 0, 0, -1, -1);
  1220.     else
  1221.         VBitmap(dst0, dstfmt).BitBlt(0, 0, &VBitmap(src0, srcfmt), 0, 0, -1, -1);
  1222. }
  1223.  
  1224. ////////////////////////////////////////////////
  1225.  
  1226. void VideoSourceAVI::invalidateFrameBuffer() {
  1227.     if (lLastFrame != -1 && hicDecomp)
  1228.         ICDecompressEnd(hicDecomp);
  1229.     lLastFrame = -1;
  1230. }
  1231.  
  1232. BOOL VideoSourceAVI::isFrameBufferValid() {
  1233.     return lLastFrame != -1;
  1234. }
  1235.  
  1236. char VideoSourceAVI::getFrameTypeChar(long lFrameNum) {
  1237.     if (lFrameNum<lSampleFirst || lFrameNum >= lSampleLast)
  1238.         return ' ';
  1239.  
  1240.     if (_isKey(lFrameNum))
  1241.         return 'K';
  1242.  
  1243.     long lBytes, lSamples;
  1244.     int err = _read(lFrameNum, 1, NULL, 0, &lBytes, &lSamples);
  1245.  
  1246.     if (err != AVIERR_OK)
  1247.         return ' ';
  1248.  
  1249.     return lBytes ? ' ' : 'D';
  1250. }
  1251.  
  1252. bool VideoSourceAVI::isStreaming() {
  1253.     return pAVIStream->isStreaming();
  1254. }
  1255.  
  1256. bool VideoSourceAVI::isKeyframeOnly() {
  1257.    return pAVIStream->isKeyframeOnly();
  1258. }
  1259.  
  1260. bool VideoSourceAVI::isType1() {
  1261.    return bIsType1;
  1262. }
  1263.  
  1264. void VideoSourceAVI::streamBegin(bool fRealTime) {
  1265.     DWORD err;
  1266.  
  1267.     stream_current_frame    = -1;
  1268.  
  1269.     pAVIStream->BeginStreaming(lSampleFirst, lSampleLast, fRealTime ? 1000 : 2000);
  1270.  
  1271.     use_ICDecompressEx = FALSE;
  1272.  
  1273.     if (hicDecomp) {
  1274.         BITMAPINFOHEADER *bih_src = bmihTemp;
  1275.         BITMAPINFOHEADER *bih_dst = getDecompressedFormat();
  1276.  
  1277.         if (ICERR_OK != (err = ICDecompressBegin(
  1278.                     hicDecomp,
  1279.                     getImageFormat(),
  1280.                     getDecompressedFormat()
  1281.                     )))
  1282.  
  1283.             if (err == ICERR_UNSUPPORTED) {
  1284.                 use_ICDecompressEx = TRUE;
  1285.  
  1286.                 err = ICDecompressExBegin(
  1287.                         hicDecomp,
  1288.                         0,
  1289.                         bih_src,
  1290.                         NULL,
  1291.                         0,0,
  1292.                         bih_src->biWidth,bih_src->biHeight,
  1293.                         bih_dst,
  1294.                         lpvBuffer,
  1295.                         0,0,
  1296.                         bih_dst->biWidth,bih_dst->biHeight
  1297.                         );
  1298.                 
  1299.             }
  1300.  
  1301.             if (ICERR_UNSUPPORTED != err && ICERR_OK != err)
  1302.                 throw MyICError("VideoSourceAVI", err);
  1303.     }
  1304. }
  1305.  
  1306. void *VideoSourceAVI::streamGetFrame(void *inputBuffer, LONG data_len, BOOL is_key, BOOL is_preroll, long frame_num) {
  1307.     DWORD err;
  1308.  
  1309.     if (!data_len) return getFrameBuffer();
  1310.  
  1311.     if (fUseGDI) {
  1312.         if (!hbmLame)
  1313.             throw MyError("Insufficient GDI resources to convert frame.");
  1314.  
  1315.         SetDIBits(NULL, hbmLame, 0, getDecompressedFormat()->biHeight, inputBuffer, (BITMAPINFO *)getFormat(),
  1316.             DIB_RGB_COLORS);
  1317.         GdiFlush();
  1318.  
  1319.     } else if (hicDecomp) {
  1320.         // Asus ASV1 crashes with zero byte frames!!!
  1321.  
  1322.         if (data_len) {
  1323.             BITMAPINFOHEADER *bih_src = bmihTemp;
  1324.             BITMAPINFOHEADER *bih_dst = getDecompressedFormat();
  1325.  
  1326.             bmihTemp->biSizeImage = data_len;
  1327.  
  1328.             VDCHECKPOINT;
  1329.             if (use_ICDecompressEx)
  1330.                 err =     ICDecompressEx(
  1331.                             hicDecomp,
  1332.     //                          (is_preroll ? ICDECOMPRESS_PREROLL : 0) |
  1333.     //                          | (data_len ? 0 : ICDECOMPRESS_NULLFRAME)
  1334.                               (is_key ? 0 : ICDECOMPRESS_NOTKEYFRAME),
  1335.                             bih_src,
  1336.                             inputBuffer,
  1337.                             0,0,
  1338.                             bih_src->biWidth, bih_src->biHeight,
  1339.                             bih_dst,
  1340.                             lpvBuffer,
  1341.                             0,0,
  1342.                             bih_dst->biWidth, bih_dst->biHeight
  1343.                             );
  1344.  
  1345.             else
  1346.                 err =     ICDecompress(
  1347.                             hicDecomp,
  1348.     //                          (is_preroll ? ICDECOMPRESS_PREROLL : 0) |
  1349.     //                          | (data_len ? 0 : ICDECOMPRESS_NULLFRAME)
  1350.                               (is_key ? 0 : ICDECOMPRESS_NOTKEYFRAME),
  1351.                             bih_src,
  1352.                             inputBuffer,
  1353.                             bih_dst,
  1354.                             lpvBuffer
  1355.                             );
  1356.             VDCHECKPOINT;
  1357.  
  1358.             if (ICERR_OK != err)
  1359.                 throw MyICError(use_ICDecompressEx ? "VideoSourceAVI [ICDecompressEx]" : "VideoSourceAVI [ICDecompress]", err);
  1360.         }
  1361.  
  1362.     } else if (mdec) {
  1363.  
  1364.         try {
  1365.             if (getDecompressedFormat()->biBitCount == 32)
  1366.                 mdec->decodeFrame32((unsigned long *)getFrameBuffer(), (unsigned char *)inputBuffer, data_len);
  1367.             else
  1368.                 mdec->decodeFrame16((unsigned long *)getFrameBuffer(), (unsigned char *)inputBuffer, data_len);
  1369.         } catch(char *s) {
  1370.             throw MyError(s);
  1371.         }
  1372.  
  1373.    } else {
  1374.       if (data_len < getImageFormat()->biSizeImage)
  1375.          throw MyError("VideoSourceAVI: uncompressed frame is short (expected %d bytes, got %d)", getImageFormat()->biSizeImage, data_len);
  1376.  
  1377.       DIBconvert(inputBuffer, getImageFormat(), getFrameBuffer(), getDecompressedFormat());
  1378.    }
  1379. //        memcpy(getFrameBuffer(), inputBuffer, getDecompressedFormat()->biSizeImage);
  1380.  
  1381.     return getFrameBuffer();
  1382. }
  1383.  
  1384. void VideoSourceAVI::streamEnd() {
  1385.  
  1386.     // If an error occurs, but no one is there to hear it, was
  1387.     // there ever really an error?
  1388.  
  1389.     if (hicDecomp) {
  1390.         if (use_ICDecompressEx)
  1391.             ICDecompressExEnd(hicDecomp);
  1392.         else
  1393.             ICDecompressEnd(hicDecomp);
  1394.     }
  1395.  
  1396.     pAVIStream->EndStreaming();
  1397.  
  1398. }
  1399.  
  1400. void *VideoSourceAVI::getFrame(LONG lFrameDesired) {
  1401.     void *dataBuffer = NULL;
  1402.     LONG dataBufferSize = 0;
  1403.     LONG lFrameKey, lFrameNum;
  1404.     LONG lBytesRead, lSamplesRead;
  1405.     DWORD err;
  1406.     int aviErr;
  1407.  
  1408.     // illegal frame number?
  1409.  
  1410.     if (lFrameDesired < lSampleFirst || lFrameDesired >= lSampleLast)
  1411.         throw MyError("VideoSourceAVI: bad frame # (%d not within [%d, %d])", lFrameDesired, lSampleFirst, lSampleLast-1);
  1412.  
  1413.     // do we already have this frame?
  1414.  
  1415.     if (lLastFrame == lFrameDesired)
  1416.         return getFrameBuffer();
  1417.  
  1418.     if (hicDecomp) {
  1419.  
  1420.         // back us off to the last key frame if we need to
  1421.  
  1422.         lFrameNum = lFrameKey = nearestKey(lFrameDesired);
  1423.  
  1424.         _RPT1(0,"Nearest key frame: %ld\n", lFrameKey);
  1425.  
  1426.         if (lLastFrame > lFrameKey && lLastFrame < lFrameDesired)
  1427.             lFrameNum = lLastFrame+1;
  1428.  
  1429.         // tell VCM we're going to do a little decompression...
  1430.  
  1431.         if (lLastFrame == -1) {
  1432.             err = ICDecompressBegin(hicDecomp, getImageFormat(), getDecompressedFormat());
  1433.             if (err != ICERR_OK) throw MyICError("VideoSourceAVI", err);
  1434.         }
  1435.     } else {
  1436.         lFrameNum = lFrameDesired;
  1437.     }
  1438.  
  1439.     _RPT2(0,"VideoSourceAVI: obtaining frame %ld, last was %ld\n", lFrameDesired, lLastFrame);
  1440.  
  1441.     try {
  1442.         do {
  1443.             _RPT1(0,"VideoSourceAVI: decompressing frame %ld\n", lFrameNum);
  1444.  
  1445.             for(;;) {
  1446.                 if (!dataBuffer)
  1447.                     aviErr = AVIERR_BUFFERTOOSMALL;
  1448.                 else
  1449.                     aviErr = read(lFrameNum, 1, dataBuffer, dataBufferSize, &lBytesRead, &lSamplesRead);
  1450.  
  1451.                 if (aviErr == AVIERR_BUFFERTOOSMALL) {
  1452.                     void *newDataBuffer;
  1453.  
  1454.                     aviErr = read(lFrameNum, 1, NULL, 0, &lBytesRead, &lSamplesRead);
  1455.  
  1456.                     if (aviErr) throw MyAVIError("VideoSourceAVI", aviErr);
  1457.  
  1458.                     dataBufferSize = (lBytesRead+65535) & -65535;
  1459.  
  1460.                     if (!(newDataBuffer = reallocmem(dataBuffer, dataBufferSize)))
  1461.                         throw MyMemoryError();
  1462.  
  1463.                     dataBuffer = newDataBuffer;
  1464.  
  1465.                 } else if (aviErr) {
  1466.                     throw MyAVIError("VideoSourceAVI", aviErr);
  1467.                 } else {
  1468. //                    if (hicDecomp || lBytesRead) break;
  1469. //                    --lFrameNum;
  1470.                     break;
  1471.                 }
  1472.             };
  1473.  
  1474.             if (!lBytesRead) continue;
  1475.  
  1476.             if (fUseGDI)
  1477.                 streamGetFrame(dataBuffer, lBytesRead, TRUE, FALSE, lFrameNum);
  1478.             else if (hicDecomp) {
  1479.                 bmihTemp->biSizeImage = lBytesRead;
  1480.  
  1481.                 if (lBytesRead) {
  1482.                     VDCHECKPOINT;
  1483.                     if (ICERR_OK != (err =     ICDecompress(
  1484.                                     hicDecomp,
  1485. //                                      (lFrameNum<lFrameDesired ? ICDECOMPRESS_PREROLL : 0) |
  1486. //                                      (lBytesRead ? 0 : ICDECOMPRESS_NULLFRAME) |
  1487.                                       (lFrameNum > lFrameKey ? ICDECOMPRESS_NOTKEYFRAME : 0),
  1488.                                     bmihTemp,
  1489.                                     dataBuffer,
  1490.                                     getDecompressedFormat(),
  1491.                                     lpvBuffer)))
  1492.  
  1493.                         throw MyICError("VideoSourceAVI", err);
  1494.                     VDCHECKPOINT;
  1495.                 }
  1496.             } else if (mdec) {
  1497.                 try {
  1498.                     if (getDecompressedFormat()->biBitCount == 32)
  1499.                         mdec->decodeFrame32((unsigned long *)getFrameBuffer(), (unsigned char *)dataBuffer, lBytesRead);
  1500.                     else
  1501.                         mdec->decodeFrame16((unsigned long *)getFrameBuffer(), (unsigned char *)dataBuffer, lBytesRead);
  1502.                 } catch(char *s) {
  1503.                     throw MyError(s);
  1504.                 }
  1505.          } else {
  1506.             if (lBytesRead < getImageFormat()->biSizeImage)
  1507.                throw MyError("VideoSourceAVI: uncompressed frame is short (expected %d bytes, got %d)", getImageFormat()->biSizeImage, lBytesRead);
  1508.  
  1509.             DIBconvert(dataBuffer, getImageFormat(), getFrameBuffer(), getDecompressedFormat());
  1510.          }
  1511. //            } else memcpy(getFrameBuffer(), dataBuffer, getDecompressedFormat()->biSizeImage);
  1512.  
  1513.         } while(++lFrameNum <= lFrameDesired);
  1514.  
  1515.     } catch(MyError e) {
  1516.         if (dataBuffer) freemem(dataBuffer);
  1517.         ICDecompressEnd(hicDecomp);
  1518.         lLastFrame = -1;
  1519.         throw e;
  1520.     }
  1521.  
  1522.     if (dataBuffer) freemem(dataBuffer);
  1523. //    if (hicDecomp) ICDecompressEnd(hicDecomp);
  1524.  
  1525.     lLastFrame = lFrameDesired; 
  1526.  
  1527.     return getFrameBuffer();
  1528. }
  1529.